package org.NooLab.glue.net.ftp;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;

import org.NooLab.glue.components.pkg.DataDeliveryPackage;
import org.NooLab.glue.components.pkg.DataDeliveryPackageIntf;
import org.NooLab.glue.net.*;
import org.NooLab.glue.net.DataSlot;
import org.NooLab.glue.net.UserData;
import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.logging.PrintLog;


/**
 * 
 * 
 * this provides a pair of embedded server and a client to send
 * 
 * such, this object allows for full-duplex communication via ftp;
 * 
 * it hides the actual ftpserver and ftpclient from the application
 * interested in exchanging data in a a reliable way
 * 
 * the FtpBox may be configured for various styles of communications
 * and preferred return types and mechanisms
 * 
 * 
 * 
 */
public class FtpBox extends Observable implements TransportBoxIntf, GlueFtpletHandlerIntf{

	private FtpServerApaj ftpServer ;
	private FtpClientApaj ftpClient ;
	
	// 
	private FtpBoxPropertiesIntf ftpBoxProperties;
	
	BoxDataIntf boxDataIntf ;
	BoxData boxData ;
	
	private boolean selfTestOn = false;
	private String selftestCompareStr="";
	
	protected DFutils fileutil = new DFutils() ;
	private PrintLog out = new PrintLog(2,false);
	
	
	
	public FtpBox( BoxDataIntf boxdata ){
		boxDataIntf = boxdata;
	}
	
	public BoxDataIntf createFtpDataContainer(){
		boxData = new BoxData( this );
		
		return (BoxDataIntf) boxData;
	}
	
	public void initialize( FtpBoxPropertiesIntf props){
		UserData boxUser = new UserData();
		 
		boxUser.setName( props.getBoxUserName() );
		boxUser.setPassword( props.getBoxUserPwd() ) ;
		boxUser.setHomeDir( props.getBoxUserDir() ) ;
		
		if (props.getLoggingLevelAlias()>=2){
			out = new PrintLog(2,true);
		}
		
		out.print(2, "creating instance of ftpServer ...  ") ;
	
		 
		ftpServer = new FtpServerApaj( props.getListeningPorts()[0], 
									   (GlueFtpletHandlerIntf)(props.getFtpDataEndpoint()), 
									   boxUser,
									   props.getLoggingLevelAlias() ) ;
		 
		
		out.print(2, "creating instance of ftpClient ... ") ;
		
		ftpClient = new FtpClientApaj( boxUser, props.getLoggingLevelAlias() );
		ftpClient.setup() ;
		
 	}
	
	public FtpBoxPropertiesIntf createFtpBoxProperties(){
		
		DataDeliveryPackage ftpDeliveryPkg = null;
		
		ftpBoxProperties = new FtpBoxProperties();
		
		ftpBoxProperties.setFtpDataEndpoint( this );
		
		ftpDeliveryPkg = new DataDeliveryPackage();
		
		// FtpDeliveryPackageIntf
		ftpBoxProperties.setFtpDeliveryPackage(ftpDeliveryPkg)  ; 
			
			
		return (FtpBoxPropertiesIntf)ftpBoxProperties ;
	}
	
	
	public void selfTest(){
		
		DataDeliveryPackageIntf testpkg ;
		InputStream istream = null ;
		String outstr = "ABC" ,str;
		
		UserData boxUser = new UserData();
		  
		
		testpkg = ftpBoxProperties.getFtpDeliveryPackage() ;
		
		testpkg.clearData();
		
		testpkg.setUsername( ftpBoxProperties.getBoxUserName()) ;
		testpkg.setPassword( ftpBoxProperties.getBoxUserPwd()) ;
		
		testpkg.setTargetAddress("localhost") ;
		testpkg.setTargetPort( ftpBoxProperties.getListeningPorts()[0]) ;
		try {
			
			istream = new ByteArrayInputStream( outstr.getBytes("UTF-8") );
			
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
		
		testpkg.setStorFilename( outstr.toLowerCase()+".dat") ;
	
		testpkg.setDataAsInputStream( istream ) ;
		
		permamentLogin( testpkg ) ;
		
		selfTestOn = true;
		long timechk = System.currentTimeMillis();
		out.print(0, "self-test : sending ...  ");
		
		send(testpkg) ;
		
		int z=0;
		while ((z<5000) && (selfTestOn == true)){
			z++;
			if (selfTestOn==true){
				delay(10);
			}
		}
		
		out.print(0, "self-test : returned. ");
		
		timechk = System.currentTimeMillis() - timechk  ;
		
		if (selftestCompareStr.contentEquals( outstr ) ){
			str="self test Ok (t="+timechk+"ms).";
		}else{
			str="self failed.";
		}
		out.print(0,str ) ;
		
		boxUser.setName( ftpBoxProperties.getBoxUserName());
		boxUser.setPassword( ftpBoxProperties.getBoxUserPwd()) ;
		boxUser.setHomeDir( ftpBoxProperties.getBoxUserDir()) ;
		 
		// restart it ;
		ftpClient = new FtpClientApaj( boxUser, ftpBoxProperties.getLoggingLevelAlias() );
		ftpClient.setup() ;
	}
	

	@SuppressWarnings("static-access")
	private void delay(int millis){
		
		try{
			Thread.currentThread().sleep(millis) ;
		}catch(Exception e){
			
		}
	}
	 
	
	public void startup( ){
		ftpServer.start();
	}
	
	public void stop(){
		ftpServer.stop() ;
		disconnectClient();
	}
	
	public void setObserver( Observer obsrvInstance){
		
		addObserver( obsrvInstance );
	}
	
	
	public void permamentLogin( DataDeliveryPackageIntf ftpPackage ){
		ftpClient.permamentLogin( ftpPackage ) ;
	}
	
	public void disconnectClient(){
		ftpClient.disconnect();
	}
	
	public void send( DataDeliveryPackageIntf ftpPackage ){
		ftpClient.send( ftpPackage );
	}
	
	public void receive(){
		
	}
	

	public void getFtpMessageStr( String msg ) {
		 
		// note, that this is called in GLueFTPlet in a FIFo buffered manner...
		// i.e. it is NOT time-critical any more here (no collisions should occur)
		out.print(2, "\ngetFtpMessageStr(str) in main : \n" );// + msg) ;
		// here we can grab the message and route it to further processing
		
		return  ;
	}

	public void getFtpMessageObj( DataSlot dataslot ) {
		String str;
		
		str = new String(dataslot.getByteArray());
		
		if (selfTestOn==false){
			
			// out.print(2, "\ngetFtpMessageStr(obj) in box : \n"+str ) ;
			boxDataIntf.getBoxData(dataslot) ;
		
		}else{
			selftestCompareStr = str ;
			selfTestOn = false ;
		}
		
		return  ;
	}

}
